home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / share / perl5 / PPI / Element.pm < prev    next >
Encoding:
Perl POD Document  |  2010-07-06  |  28.2 KB  |  1,127 lines

  1. package PPI::Element;
  2.  
  3. =pod
  4.  
  5. =head1 NAME
  6.  
  7. PPI::Element - The abstract Element class, a base for all source objects
  8.  
  9. =head1 INHERITANCE
  10.  
  11.   PPI::Element is the root of the PDOM tree
  12.  
  13. =head1 DESCRIPTION
  14.  
  15. The abstract C<PPI::Element> serves as a base class for all source-related
  16. objects, from a single whitespace token to an entire document. It provides
  17. a basic set of methods to provide a common interface and basic
  18. implementations.
  19.  
  20. =head1 METHODS
  21.  
  22. =cut
  23.  
  24. use strict;
  25. use Clone           ();
  26. use Scalar::Util    qw{refaddr};
  27. use Params::Util    qw{_INSTANCE _ARRAY};
  28. use List::MoreUtils ();
  29. use PPI::Util       ();
  30. use PPI::Node       ();
  31.  
  32. use vars qw{$VERSION $errstr %_PARENT};
  33. BEGIN {
  34.     $VERSION = '1.213';
  35.     $errstr  = '';
  36.  
  37.     # Master Child -> Parent index
  38.     %_PARENT = ();
  39. }
  40.  
  41. use overload 'bool' => \&PPI::Util::TRUE;
  42. use overload '""'   => 'content';
  43. use overload '=='   => '__equals';
  44. use overload '!='   => '__nequals';
  45. use overload 'eq'   => '__eq';
  46. use overload 'ne'   => '__ne';
  47.  
  48.  
  49.  
  50.  
  51.  
  52. #####################################################################
  53. # General Properties
  54.  
  55. =pod
  56.  
  57. =head2 significant
  58.  
  59. Because we treat whitespace and other non-code items as Tokens (in order to
  60. be able to "round trip" the L<PPI::Document> back to a file) the
  61. C<significant> method allows us to distinguish between tokens that form a
  62. part of the code, and tokens that aren't significant, such as whitespace,
  63. POD, or the portion of a file after (and including) the C<__END__> token.
  64.  
  65. Returns true if the Element is significant, or false it not.
  66.  
  67. =cut
  68.  
  69. ### XS -> PPI/XS.xs:_PPI_Element__significant 0.845+
  70. sub significant { 1 }
  71.  
  72. =pod
  73.  
  74. =head2 class
  75.  
  76. The C<class> method is provided as a convenience, and really does nothing
  77. more than returning C<ref($self)>. However, some people have found that
  78. they appreciate the laziness of C<$Foo-E<gt>class eq 'whatever'>, so I
  79. have caved to popular demand and included it.
  80.  
  81. Returns the class of the Element as a string
  82.  
  83. =cut
  84.  
  85. sub class { ref($_[0]) }
  86.  
  87. =pod
  88.  
  89. =head2 tokens
  90.  
  91. The C<tokens> method returns a list of L<PPI::Token> objects for the
  92. Element, essentially getting back that part of the document as if it had
  93. not been lexed.
  94.  
  95. This also means there are no Statements and no Structures in the list,
  96. just the Token classes.
  97.  
  98. =cut
  99.  
  100. sub tokens { $_[0] }
  101.  
  102. =pod
  103.  
  104. =head2 content
  105.  
  106. For B<any> C<PPI::Element>, the C<content> method will reconstitute the
  107. base code for it as a single string. This method is also the method used
  108. for overloading stringification. When an Element is used in a double-quoted
  109. string for example, this is the method that is called.
  110.  
  111. B<WARNING:>
  112.  
  113. You should be aware that because of the way that here-docs are handled, any
  114. here-doc content is not included in C<content>, and as such you should
  115. B<not> eval or execute the result if it contains any L<PPI::Token::HereDoc>.
  116.  
  117. The L<PPI::Document> method C<serialize> should be used to stringify a PDOM
  118. document into something that can be executed as expected.
  119.  
  120. Returns the basic code as a string (excluding here-doc content).
  121.  
  122. =cut
  123.  
  124. ### XS -> PPI/XS.xs:_PPI_Element__content 0.900+
  125. sub content { '' }
  126.  
  127.  
  128.  
  129.  
  130.  
  131. #####################################################################
  132. # Naigation Methods
  133.  
  134. =pod
  135.  
  136. =head2 parent
  137.  
  138. Elements themselves are not intended to contain other Elements, that is
  139. left to the L<PPI::Node> abstract class, a subclass of C<PPI::Element>.
  140. However, all Elements can be contained B<within> a parent Node.
  141.  
  142. If an Element is within a parent Node, the C<parent> method returns the
  143. Node.
  144.  
  145. =cut
  146.  
  147. sub parent { $_PARENT{refaddr $_[0]} }
  148.  
  149. =pod
  150.  
  151. =head2 descendant_of $element
  152.  
  153. Answers whether a C<PPI::Element> is contained within another one.
  154.  
  155. C<PPI::Element>s are considered to be descendants of themselves.
  156.  
  157. =begin testing descendant_of 9
  158.  
  159. my $Document = PPI::Document->new( \'( [ thingy ] ); $blarg = 1' );
  160. isa_ok( $Document, 'PPI::Document' );
  161. ok(
  162.     $Document->descendant_of($Document),
  163.     'Document is a descendant of itself.',
  164. );
  165.  
  166. my $words = $Document->find('Token::Word');
  167. is(scalar @{$words}, 1, 'Document contains 1 Word.');
  168. my $word = $words->[0];
  169. ok(
  170.     $word->descendant_of($word),
  171.     'Word is a descendant of itself.',
  172. );
  173. ok(
  174.     $word->descendant_of($Document),
  175.     'Word is a descendant of the Document.',
  176. );
  177. ok(
  178.     ! $Document->descendant_of($word),
  179.     'Document is not a descendant of the Word.',
  180. );
  181.  
  182. my $symbols = $Document->find('Token::Symbol');
  183. is(scalar @{$symbols}, 1, 'Document contains 1 Symbol.');
  184. my $symbol = $symbols->[0];
  185. ok(
  186.     ! $word->descendant_of($symbol),
  187.     'Word is not a descendant the Symbol.',
  188. );
  189. ok(
  190.     ! $symbol->descendant_of($word),
  191.     'Symbol is not a descendant the Word.',
  192. );
  193.  
  194. =end testing
  195.  
  196. =cut
  197.  
  198. sub descendant_of {
  199.     my $cursor = shift;
  200.     my $parent = shift or return undef;
  201.     while ( refaddr $cursor != refaddr $parent ) {
  202.         $cursor = $_PARENT{refaddr $cursor} or return '';
  203.     }
  204.     return 1;
  205. }
  206.  
  207. =pod
  208.  
  209. =head2 ancestor_of $element
  210.  
  211. Answers whether a C<PPI::Element> is contains another one.
  212.  
  213. C<PPI::Element>s are considered to be ancestors of themselves.
  214.  
  215. =begin testing ancestor_of 9
  216.  
  217. my $Document = PPI::Document->new( \'( [ thingy ] ); $blarg = 1' );
  218. isa_ok( $Document, 'PPI::Document' );
  219. ok(
  220.     $Document->ancestor_of($Document),
  221.     'Document is an ancestor of itself.',
  222. );
  223.  
  224. my $words = $Document->find('Token::Word');
  225. is(scalar @{$words}, 1, 'Document contains 1 Word.');
  226. my $word = $words->[0];
  227. ok(
  228.     $word->ancestor_of($word),
  229.     'Word is an ancestor of itself.',
  230. );
  231. ok(
  232.     ! $word->ancestor_of($Document),
  233.     'Word is not an ancestor of the Document.',
  234. );
  235. ok(
  236.     $Document->ancestor_of($word),
  237.     'Document is an ancestor of the Word.',
  238. );
  239.  
  240. my $symbols = $Document->find('Token::Symbol');
  241. is(scalar @{$symbols}, 1, 'Document contains 1 Symbol.');
  242. my $symbol = $symbols->[0];
  243. ok(
  244.     ! $word->ancestor_of($symbol),
  245.     'Word is not an ancestor the Symbol.',
  246. );
  247. ok(
  248.     ! $symbol->ancestor_of($word),
  249.     'Symbol is not an ancestor the Word.',
  250. );
  251.  
  252. =end testing
  253.  
  254. =cut
  255.  
  256. sub ancestor_of {
  257.     my $self   = shift;
  258.     my $cursor = shift or return undef;
  259.     while ( refaddr $cursor != refaddr $self ) {
  260.         $cursor = $_PARENT{refaddr $cursor} or return '';
  261.     }
  262.     return 1;
  263. }
  264.  
  265. =pod
  266.  
  267. =head2 statement
  268.  
  269. For a C<PPI::Element> that is contained (at some depth) within a
  270. L<PPI::Statment>, the C<statement> method will return the first parent
  271. Statement object lexically 'above' the Element.
  272.  
  273. Returns a L<PPI::Statement> object, which may be the same Element if the
  274. Element is itself a L<PPI::Statement> object.
  275.  
  276. Returns false if the Element is not within a Statement and is not itself
  277. a Statement.
  278.  
  279. =cut
  280.  
  281. sub statement {
  282.     my $cursor = shift;
  283.     while ( ! _INSTANCE($cursor, 'PPI::Statement') ) {
  284.         $cursor = $_PARENT{refaddr $cursor} or return '';
  285.     }
  286.     $cursor;
  287. }
  288.  
  289. =pod
  290.  
  291. =head2 top
  292.  
  293. For a C<PPI::Element> that is contained within a PDOM tree, the C<top> method
  294. will return the top-level Node in the tree. Most of the time this should be
  295. a L<PPI::Document> object, however this will not always be so. For example,
  296. if a subroutine has been removed from its Document, to be moved to another
  297. Document.
  298.  
  299. Returns the top-most PDOM object, which may be the same Element, if it is
  300. not within any parent PDOM object.
  301.  
  302. =cut
  303.  
  304. sub top {
  305.     my $cursor = shift;
  306.     while ( my $parent = $_PARENT{refaddr $cursor} ) {
  307.         $cursor = $parent;
  308.     }
  309.     $cursor;
  310. }
  311.  
  312. =pod
  313.  
  314. =head2 document
  315.  
  316. For an Element that is contained within a L<PPI::Document> object,
  317. the C<document> method will return the top-level Document for the Element.
  318.  
  319. Returns the L<PPI::Document> for this Element, or false if the Element is not
  320. contained within a Document.
  321.  
  322. =cut
  323.  
  324. sub document {
  325.     my $top = shift->top;
  326.     _INSTANCE($top, 'PPI::Document') and $top;
  327. }
  328.  
  329. =pod
  330.  
  331. =head2 next_sibling
  332.  
  333. All L<PPI::Node> objects (specifically, our parent Node) contain a number of
  334. C<PPI::Element> objects. The C<next_sibling> method returns the C<PPI::Element>
  335. immediately after the current one, or false if there is no next sibling.
  336.  
  337. =cut
  338.  
  339. sub next_sibling {
  340.     my $self     = shift;
  341.     my $parent   = $_PARENT{refaddr $self} or return '';
  342.     my $key      = refaddr $self;
  343.     my $elements = $parent->{children};
  344.     my $position = List::MoreUtils::firstidx {
  345.         refaddr $_ == $key
  346.         } @$elements;
  347.     $elements->[$position + 1] || '';
  348. }
  349.  
  350. =pod
  351.  
  352. =head2 snext_sibling
  353.  
  354. As per the other 's' methods, the C<snext_sibling> method returns the next
  355. B<significant> sibling of the C<PPI::Element> object.
  356.  
  357. Returns a C<PPI::Element> object, or false if there is no 'next' significant
  358. sibling.
  359.  
  360. =cut
  361.  
  362. sub snext_sibling {
  363.     my $self     = shift;
  364.     my $parent   = $_PARENT{refaddr $self} or return '';
  365.     my $key      = refaddr $self;
  366.     my $elements = $parent->{children};
  367.     my $position = List::MoreUtils::firstidx {
  368.         refaddr $_ == $key
  369.         } @$elements;
  370.     while ( defined(my $it = $elements->[++$position]) ) {
  371.         return $it if $it->significant;
  372.     }
  373.     '';
  374. }
  375.  
  376. =pod
  377.  
  378. =head2 previous_sibling
  379.  
  380. All L<PPI::Node> objects (specifically, our parent Node) contain a number of
  381. C<PPI::Element> objects. The C<previous_sibling> method returns the Element
  382. immediately before the current one, or false if there is no 'previous'
  383. C<PPI::Element> object.
  384.  
  385. =cut
  386.  
  387. sub previous_sibling {
  388.     my $self     = shift;
  389.     my $parent   = $_PARENT{refaddr $self} or return '';
  390.     my $key      = refaddr $self;
  391.     my $elements = $parent->{children};
  392.     my $position = List::MoreUtils::firstidx {
  393.         refaddr $_ == $key
  394.         } @$elements;
  395.     $position and $elements->[$position - 1] or '';
  396. }
  397.  
  398. =pod
  399.  
  400. =head2 sprevious_sibling
  401.  
  402. As per the other 's' methods, the C<sprevious_sibling> method returns
  403. the previous B<significant> sibling of the C<PPI::Element> object.
  404.  
  405. Returns a C<PPI::Element> object, or false if there is no 'previous' significant
  406. sibling.
  407.  
  408. =cut
  409.  
  410. sub sprevious_sibling {
  411.     my $self     = shift;
  412.     my $parent   = $_PARENT{refaddr $self} or return '';
  413.     my $key      = refaddr $self;
  414.     my $elements = $parent->{children};
  415.     my $position = List::MoreUtils::firstidx {
  416.         refaddr $_ == $key
  417.         } @$elements;
  418.     while ( $position-- and defined(my $it = $elements->[$position]) ) {
  419.         return $it if $it->significant;
  420.     }
  421.     '';
  422. }
  423.  
  424. =pod
  425.  
  426. =head2 first_token
  427.  
  428. As a support method for higher-order algorithms that deal specifically with
  429. tokens and actual Perl content, the C<first_token> method finds the first
  430. PPI::Token object within or equal to this one.
  431.  
  432. That is, if called on a L<PPI::Node> subclass, it will descend until it
  433. finds a L<PPI::Token>. If called on a L<PPI::Token> object, it will return
  434. the same object.
  435.  
  436. Returns a L<PPI::Token> object, or dies on error (which should be extremely
  437. rare and only occur if an illegal empty L<PPI::Statement> exists below the
  438. current Element somewhere.
  439.  
  440. =cut
  441.  
  442. sub first_token {
  443.     my $cursor = shift;
  444.     while ( $cursor->isa('PPI::Node') ) {
  445.         $cursor = $cursor->first_element
  446.         or die "Found empty PPI::Node while getting first token";
  447.     }
  448.     $cursor;
  449. }
  450.  
  451.  
  452. =pod
  453.  
  454. =head2 last_token
  455.  
  456. As a support method for higher-order algorithms that deal specifically with
  457. tokens and actual Perl content, the C<last_token> method finds the last
  458. PPI::Token object within or equal to this one.
  459.  
  460. That is, if called on a L<PPI::Node> subclass, it will descend until it
  461. finds a L<PPI::Token>. If called on a L<PPI::Token> object, it will return
  462. the itself.
  463.  
  464. Returns a L<PPI::Token> object, or dies on error (which should be extremely
  465. rare and only occur if an illegal empty L<PPI::Statement> exists below the
  466. current Element somewhere.
  467.  
  468. =cut
  469.  
  470. sub last_token {
  471.     my $cursor = shift;
  472.     while ( $cursor->isa('PPI::Node') ) {
  473.         $cursor = $cursor->last_element
  474.         or die "Found empty PPI::Node while getting first token";
  475.     }
  476.     $cursor;
  477. }
  478.  
  479. =pod
  480.  
  481. =head2 next_token
  482.  
  483. As a support method for higher-order algorithms that deal specifically with
  484. tokens and actual Perl content, the C<next_token> method finds the
  485. L<PPI::Token> object that is immediately after the current Element, even if
  486. it is not within the same parent L<PPI::Node> as the one for which the
  487. method is being called.
  488.  
  489. Note that this is B<not> defined as a L<PPI::Token>-specific method,
  490. because it can be useful to find the next token that is after, say, a
  491. L<PPI::Statement>, although obviously it would be useless to want the
  492. next token after a L<PPI::Document>.
  493.  
  494. Returns a L<PPI::Token> object, or false if there are no more tokens after
  495. the Element.
  496.  
  497. =cut
  498.  
  499. sub next_token {
  500.     my $cursor = shift;
  501.  
  502.     # Find the next element, going upwards as needed
  503.     while ( 1 ) {
  504.         my $element = $cursor->next_sibling;
  505.         if ( $element ) {
  506.             return $element if $element->isa('PPI::Token');
  507.             return $element->first_token;
  508.         }
  509.         $cursor = $cursor->parent or return '';
  510.         if ( $cursor->isa('PPI::Structure') and $cursor->finish ) {
  511.             return $cursor->finish;
  512.         }
  513.     }
  514. }
  515.  
  516. =pod
  517.  
  518. =head2 previous_token
  519.  
  520. As a support method for higher-order algorithms that deal specifically with
  521. tokens and actual Perl content, the C<previous_token> method finds the
  522. L<PPI::Token> object that is immediately before the current Element, even
  523. if it is not within the same parent L<PPI::Node> as this one.
  524.  
  525. Note that this is not defined as a L<PPI::Token>-only method, because it can
  526. be useful to find the token is before, say, a L<PPI::Statement>, although
  527. obviously it would be useless to want the next token before a
  528. L<PPI::Document>.
  529.  
  530. Returns a L<PPI::Token> object, or false if there are no more tokens before
  531. the C<Element>.
  532.  
  533. =cut
  534.  
  535. sub previous_token {
  536.     my $cursor = shift;
  537.  
  538.     # Find the previous element, going upwards as needed
  539.     while ( 1 ) {
  540.         my $element = $cursor->previous_sibling;
  541.         if ( $element ) {
  542.             return $element if $element->isa('PPI::Token');
  543.             return $element->last_token;
  544.         }
  545.         $cursor = $cursor->parent or return '';
  546.         if ( $cursor->isa('PPI::Structure') and $cursor->start ) {
  547.             return $cursor->start;
  548.         }
  549.     }
  550. }
  551.  
  552.  
  553.  
  554.  
  555.  
  556. #####################################################################
  557. # Manipulation
  558.  
  559. =pod
  560.  
  561. =head2 clone
  562.  
  563. As per the L<Clone> module, the C<clone> method makes a perfect copy of
  564. an Element object. In the generic case, the implementation is done using
  565. the L<Clone> module's mechanism itself. In higher-order cases, such as for
  566. Nodes, there is more work involved to keep the parent-child links intact.
  567.  
  568. =cut
  569.  
  570. sub clone {
  571.     Clone::clone(shift);
  572. }
  573.  
  574. =pod
  575.  
  576. =head2 insert_before @Elements
  577.  
  578. The C<insert_before> method allows you to insert lexical perl content, in
  579. the form of C<PPI::Element> objects, before the calling C<Element>. You
  580. need to be very careful when modifying perl code, as it's easy to break
  581. things.
  582.  
  583. In its initial incarnation, this method allows you to insert a single
  584. Element, and will perform some basic checking to prevent you inserting
  585. something that would be structurally wrong (in PDOM terms).
  586.  
  587. In future, this method may be enhanced to allow the insertion of multiple
  588. Elements, inline-parsed code strings or L<PPI::Document::Fragment> objects.
  589.  
  590. Returns true if the Element was inserted, false if it can not be inserted,
  591. or C<undef> if you do not provide a L<PPI::Element> object as a parameter.
  592.  
  593. =begin testing __insert_before 6
  594.  
  595. my $Document = PPI::Document->new( \"print 'Hello World';" );
  596. isa_ok( $Document, 'PPI::Document' );
  597. my $semi = $Document->find_first('Token::Structure');
  598. isa_ok( $semi, 'PPI::Token::Structure' );
  599. is( $semi->content, ';', 'Got expected token' );
  600. my $foo = PPI::Token::Word->new('foo');
  601. isa_ok( $foo, 'PPI::Token::Word' );
  602. is( $foo->content, 'foo', 'Created Word token' );
  603. $semi->__insert_before( $foo );
  604. is( $Document->serialize, "print 'Hello World'foo;",
  605.     '__insert_before actually inserts' );
  606.  
  607. =end testing
  608.  
  609. =begin testing insert_before after __insert_before 6
  610.  
  611. my $Document = PPI::Document->new( \"print 'Hello World';" );
  612. isa_ok( $Document, 'PPI::Document' );
  613. my $semi = $Document->find_first('Token::Structure');
  614. isa_ok( $semi, 'PPI::Token::Structure' );
  615. is( $semi->content, ';', 'Got expected token' );
  616. my $foo = PPI::Token::Word->new('foo');
  617. isa_ok( $foo, 'PPI::Token::Word' );
  618. is( $foo->content, 'foo', 'Created Word token' );
  619. $semi->insert_before( $foo );
  620. is( $Document->serialize, "print 'Hello World'foo;",
  621.     'insert_before actually inserts' );
  622.  
  623. =end testing
  624.  
  625. =cut
  626.  
  627. sub __insert_before {
  628.     my $self = shift;
  629.     $self->parent->__insert_before_child( $self, @_ );
  630. }
  631.  
  632. =pod
  633.  
  634. =head2 insert_after @Elements
  635.  
  636. The C<insert_after> method allows you to insert lexical perl content, in
  637. the form of C<PPI::Element> objects, after the calling C<Element>. You need
  638. to be very careful when modifying perl code, as it's easy to break things.
  639.  
  640. In its initial incarnation, this method allows you to insert a single
  641. Element, and will perform some basic checking to prevent you inserting
  642. something that would be structurally wrong (in PDOM terms).
  643.  
  644. In future, this method may be enhanced to allow the insertion of multiple
  645. Elements, inline-parsed code strings or L<PPI::Document::Fragment> objects.
  646.  
  647. Returns true if the Element was inserted, false if it can not be inserted,
  648. or C<undef> if you do not provide a L<PPI::Element> object as a parameter.
  649.  
  650. =begin testing __insert_after 6
  651.  
  652. my $Document = PPI::Document->new( \"print 'Hello World';" );
  653. isa_ok( $Document, 'PPI::Document' );
  654. my $string = $Document->find_first('Token::Quote');
  655. isa_ok( $string, 'PPI::Token::Quote' );
  656. is( $string->content, "'Hello World'", 'Got expected token' );
  657. my $foo = PPI::Token::Word->new('foo');
  658. isa_ok( $foo, 'PPI::Token::Word' );
  659. is( $foo->content, 'foo', 'Created Word token' );
  660. $string->__insert_after( $foo );
  661. is( $Document->serialize, "print 'Hello World'foo;",
  662.     '__insert_after actually inserts' );
  663.  
  664. =end testing
  665.  
  666. =begin testing insert_after after __insert_after 6
  667.  
  668. my $Document = PPI::Document->new( \"print 'Hello World';" );
  669. isa_ok( $Document, 'PPI::Document' );
  670. my $string = $Document->find_first('Token::Quote');
  671. isa_ok( $string, 'PPI::Token::Quote' );
  672. is( $string->content, "'Hello World'", 'Got expected token' );
  673. my $foo = PPI::Token::Word->new('foo');
  674. isa_ok( $foo, 'PPI::Token::Word' );
  675. is( $foo->content, 'foo', 'Created Word token' );
  676. $string->insert_after( $foo );
  677. is( $Document->serialize, "print 'Hello World'foo;",
  678.     'insert_after actually inserts' );
  679.  
  680. =end testing
  681.  
  682. =cut
  683.  
  684. sub __insert_after {
  685.     my $self = shift;
  686.     $self->parent->__insert_after_child( $self, @_ );
  687. }
  688.  
  689. =pod
  690.  
  691. =head2 remove
  692.  
  693. For a given C<PPI::Element>, the C<remove> method will remove it from its
  694. parent B<intact>, along with all of its children.
  695.  
  696. Returns the C<Element> itself as a convenience, or C<undef> if an error
  697. occurs while trying to remove the C<Element>.
  698.  
  699. =cut
  700.  
  701. sub remove {
  702.     my $self   = shift;
  703.     my $parent = $self->parent or return $self;
  704.     $parent->remove_child( $self );
  705. }
  706.  
  707. =pod
  708.  
  709. =head2 delete
  710.  
  711. For a given C<PPI::Element>, the C<delete> method will remove it from its
  712. parent, immediately deleting the C<Element> and all of its children (if it
  713. has any).
  714.  
  715. Returns true if the C<Element> was successfully deleted, or C<undef> if
  716. an error occurs while trying to remove the C<Element>.
  717.  
  718. =cut
  719.  
  720. sub delete {
  721.     $_[0]->remove or return undef;
  722.     $_[0]->DESTROY;
  723.     1;
  724. }
  725.  
  726. =pod
  727.  
  728. =head2 replace $Element
  729.  
  730. Although some higher level class support more exotic forms of replace,
  731. at the basic level the C<replace> method takes a single C<Element> as
  732. an argument and replaces the current C<Element> with it.
  733.  
  734. To prevent accidental damage to code, in this initial implementation the
  735. replacement element B<must> be of the same class (or a subclass) as the
  736. one being replaced.
  737.  
  738. =cut
  739.  
  740. sub replace {
  741.     my $self    = ref $_[0] ? shift : return undef;
  742.     my $Element = _INSTANCE(shift, ref $self) or return undef;
  743.     die "The ->replace method has not yet been implemented";
  744. }
  745.  
  746. =pod
  747.  
  748. =head2 location
  749.  
  750. If the Element exists within a L<PPI::Document> that has
  751. indexed the Element locations using C<PPI::Document::index_locations>, the
  752. C<location> method will return the location of the first character of the
  753. Element within the Document.
  754.  
  755. Returns the location as a reference to a five-element array in the form C<[
  756. $line, $rowchar, $col, $logical_line, $logical_file_name ]>. The values are in
  757. a human format, with the first character of the file located at C<[ 1, 1, 1, ?,
  758. 'something' ]>.
  759.  
  760. The second and third numbers are similar, except that the second is the
  761. literal horizontal character, and the third is the visual column, taking
  762. into account tabbing (see L<PPI::Document/"tab_width [ $width ]">).
  763.  
  764. The fourth number is the line number, taking into account any C<#line>
  765. directives.  The fifth element is the name of the file that the element was
  766. found in, if available, taking into account any C<#line> directives.
  767.  
  768. Returns C<undef> on error, or if the L<PPI::Document> object has not been
  769. indexed.
  770.  
  771. =cut
  772.  
  773. sub location {
  774.     my $self = shift;
  775.  
  776.     $self->_ensure_location_present or return undef;
  777.  
  778.     # Return a copy, not the original
  779.     return [ @{$self->{_location}} ];
  780. }
  781.  
  782. =pod
  783.  
  784. =head2 line_number
  785.  
  786. If the Element exists within a L<PPI::Document> that has indexed the Element
  787. locations using C<PPI::Document::index_locations>, the C<line_number> method
  788. will return the line number of the first character of the Element within the
  789. Document.
  790.  
  791. Returns C<undef> on error, or if the L<PPI::Document> object has not been
  792. indexed.
  793.  
  794. =begin testing line_number 3
  795.  
  796. my $document = PPI::Document->new(\<<'END_PERL');
  797.  
  798.  
  799.    foo
  800. END_PERL
  801.  
  802. isa_ok( $document, 'PPI::Document' );
  803. my $words = $document->find('PPI::Token::Word');
  804. is( scalar @{$words}, 1, 'Found expected word token.' );
  805. is( $words->[0]->line_number, 3, 'Got correct line number.' );
  806.  
  807. =end testing
  808.  
  809. =cut
  810.  
  811. sub line_number {
  812.     my $self = shift;
  813.  
  814.     my $location = $self->location() or return undef;
  815.     return $location->[0];
  816. }
  817.  
  818. =pod
  819.  
  820. =head2 column_number
  821.  
  822. If the Element exists within a L<PPI::Document> that has indexed the Element
  823. locations using C<PPI::Document::index_locations>, the C<column_number> method
  824. will return the column number of the first character of the Element within the
  825. Document.
  826.  
  827. Returns C<undef> on error, or if the L<PPI::Document> object has not been
  828. indexed.
  829.  
  830. =begin testing column_number 3
  831.  
  832. my $document = PPI::Document->new(\<<'END_PERL');
  833.  
  834.  
  835.    foo
  836. END_PERL
  837.  
  838. isa_ok( $document, 'PPI::Document' );
  839. my $words = $document->find('PPI::Token::Word');
  840. is( scalar @{$words}, 1, 'Found expected word token.' );
  841. is( $words->[0]->column_number, 4, 'Got correct column number.' );
  842.  
  843. =end testing
  844.  
  845. =cut
  846.  
  847. sub column_number {
  848.     my $self = shift;
  849.  
  850.     my $location = $self->location() or return undef;
  851.     return $location->[1];
  852. }
  853.  
  854. =pod
  855.  
  856. =head2 visual_column_number
  857.  
  858. If the Element exists within a L<PPI::Document> that has indexed the Element
  859. locations using C<PPI::Document::index_locations>, the C<visual_column_number>
  860. method will return the visual column number of the first character of the
  861. Element within the Document, according to the value of
  862. L<PPI::Document/"tab_width [ $width ]">.
  863.  
  864. Returns C<undef> on error, or if the L<PPI::Document> object has not been
  865. indexed.
  866.  
  867. =begin testing visual_column_number 3
  868.  
  869. my $document = PPI::Document->new(\<<"END_PERL");
  870.  
  871.  
  872. \t foo
  873. END_PERL
  874.  
  875. isa_ok( $document, 'PPI::Document' );
  876. my $tab_width = 5;
  877. $document->tab_width($tab_width);  # don't use a "usual" value.
  878. my $words = $document->find('PPI::Token::Word');
  879. is( scalar @{$words}, 1, 'Found expected word token.' );
  880. is(
  881.     $words->[0]->visual_column_number,
  882.     $tab_width + 2,
  883.     'Got correct visual column number.',
  884. );
  885.  
  886. =end testing
  887.  
  888. =cut
  889.  
  890. sub visual_column_number {
  891.     my $self = shift;
  892.  
  893.     my $location = $self->location() or return undef;
  894.     return $location->[2];
  895. }
  896.  
  897. =pod
  898.  
  899. =head2 logical_line_number
  900.  
  901. If the Element exists within a L<PPI::Document> that has indexed the Element
  902. locations using C<PPI::Document::index_locations>, the C<logical_line_number>
  903. method will return the line number of the first character of the Element within
  904. the Document, taking into account any C<#line> directives.
  905.  
  906. Returns C<undef> on error, or if the L<PPI::Document> object has not been
  907. indexed.
  908.  
  909. =begin testing logical_line_number 3
  910.  
  911. # Double quoted so that we don't really have a "#line" at the beginning and
  912. # errors in this file itself aren't affected by this.
  913. my $document = PPI::Document->new(\<<"END_PERL");
  914.  
  915.  
  916. \#line 1 test-file
  917.    foo
  918. END_PERL
  919.  
  920. isa_ok( $document, 'PPI::Document' );
  921. my $words = $document->find('PPI::Token::Word');
  922. is( scalar @{$words}, 1, 'Found expected word token.' );
  923. is( $words->[0]->logical_line_number, 1, 'Got correct logical line number.' );
  924.  
  925. =end testing
  926.  
  927. =cut
  928.  
  929. sub logical_line_number {
  930.     my $self = shift;
  931.  
  932.     return $self->location()->[3];
  933. }
  934.  
  935. =pod
  936.  
  937. =head2 logical_filename
  938.  
  939. If the Element exists within a L<PPI::Document> that has indexed the Element
  940. locations using C<PPI::Document::index_locations>, the C<logical_filename>
  941. method will return the logical file name containing the first character of the
  942. Element within the Document, taking into account any C<#line> directives.
  943.  
  944. Returns C<undef> on error, or if the L<PPI::Document> object has not been
  945. indexed.
  946.  
  947. =begin testing logical_filename 3
  948.  
  949. # Double quoted so that we don't really have a "#line" at the beginning and
  950. # errors in this file itself aren't affected by this.
  951. my $document = PPI::Document->new(\<<"END_PERL");
  952.  
  953.  
  954. \#line 1 test-file
  955.    foo
  956. END_PERL
  957.  
  958. isa_ok( $document, 'PPI::Document' );
  959. my $words = $document->find('PPI::Token::Word');
  960. is( scalar @{$words}, 1, 'Found expected word token.' );
  961. is(
  962.     $words->[0]->logical_filename,
  963.     'test-file',
  964.     'Got correct logical line number.',
  965. );
  966.  
  967. =end testing
  968.  
  969. =cut
  970.  
  971. sub logical_filename {
  972.     my $self = shift;
  973.  
  974.     my $location = $self->location() or return undef;
  975.     return $location->[4];
  976. }
  977.  
  978. sub _ensure_location_present {
  979.     my $self = shift;
  980.  
  981.     unless ( exists $self->{_location} ) {
  982.         # Are we inside a normal document?
  983.         my $Document = $self->document or return undef;
  984.         if ( $Document->isa('PPI::Document::Fragment') ) {
  985.             # Because they can't be serialized, document fragments
  986.             # do not support the concept of location.
  987.             return undef;
  988.         }
  989.  
  990.         # Generate the locations. If they need one location, then
  991.         # the chances are they'll want more, and it's better that
  992.         # everything is already pre-generated.
  993.         $Document->index_locations or return undef;
  994.         unless ( exists $self->{_location} ) {
  995.             # erm... something went very wrong here
  996.             return undef;
  997.         }
  998.     }
  999.  
  1000.     return 1;
  1001. }
  1002.  
  1003. # Although flush_locations is only publically a Document-level method,
  1004. # we are able to implement it at an Element level, allowing us to
  1005. # selectively flush only the part of the document that occurs after the
  1006. # element for which the flush is called.
  1007. sub _flush_locations {
  1008.     my $self  = shift;
  1009.     unless ( $self == $self->top ) {
  1010.         return $self->top->_flush_locations( $self );
  1011.     }
  1012.  
  1013.     # Get the full list of all Tokens
  1014.     my @Tokens = $self->tokens;
  1015.  
  1016.     # Optionally allow starting from an arbitrary element (or rather,
  1017.     # the first Token equal-to-or-within an arbitrary element)
  1018.     if ( _INSTANCE($_[0], 'PPI::Element') ) {
  1019.         my $start = shift->first_token;
  1020.         while ( my $Token = shift @Tokens ) {
  1021.             return 1 unless $Token->{_location};
  1022.             next unless refaddr($Token) == refaddr($start);
  1023.  
  1024.             # Found the start. Flush it's location
  1025.             delete $$Token->{_location};
  1026.             last;
  1027.         }
  1028.     }
  1029.  
  1030.     # Iterate over any remaining Tokens and flush their location
  1031.     foreach my $Token ( @Tokens ) {
  1032.         delete $Token->{_location};
  1033.     }
  1034.  
  1035.     1;
  1036. }
  1037.  
  1038.  
  1039.  
  1040.  
  1041.  
  1042. #####################################################################
  1043. # XML Compatibility Methods
  1044.  
  1045. sub _xml_name {
  1046.     my $class = ref $_[0] || $_[0];
  1047.     my $name  = lc join( '_', split /::/, $class );
  1048.     substr($name, 4);
  1049. }
  1050.  
  1051. sub _xml_attr {
  1052.     return {};
  1053. }
  1054.  
  1055. sub _xml_content {
  1056.     defined $_[0]->{content} ? $_[0]->{content} : '';
  1057. }
  1058.  
  1059.  
  1060.  
  1061.  
  1062.  
  1063. #####################################################################
  1064. # Internals
  1065.  
  1066. # Set the error string
  1067. sub _error {
  1068.     $errstr = $_[1];
  1069.     undef;
  1070. }
  1071.  
  1072. # Clear the error string
  1073. sub _clear {
  1074.     $errstr = '';
  1075.     $_[0];
  1076. }
  1077.  
  1078. # Being DESTROYed in this manner, rather than by an explicit
  1079. # ->delete means our reference count has probably fallen to zero.
  1080. # Therefore we don't need to remove ourselves from our parent,
  1081. # just the index ( just in case ).
  1082. ### XS -> PPI/XS.xs:_PPI_Element__DESTROY 0.900+
  1083. sub DESTROY { delete $_PARENT{refaddr $_[0]} }
  1084.  
  1085. # Operator overloads
  1086. sub __equals  { ref $_[1] and refaddr($_[0]) == refaddr($_[1]) }
  1087. sub __nequals { !__equals(@_) }
  1088. sub __eq {
  1089.     my $self  = _INSTANCE($_[0], 'PPI::Element') ? $_[0]->content : $_[0];
  1090.     my $other = _INSTANCE($_[1], 'PPI::Element') ? $_[1]->content : $_[1];
  1091.     $self eq $other;
  1092. }
  1093. sub __ne { !__eq(@_) }
  1094.  
  1095. 1;
  1096.  
  1097. =pod
  1098.  
  1099. =head1 TO DO
  1100.  
  1101. It would be nice if C<location> could be used in an ad-hoc manner. That is,
  1102. if called on an Element within a Document that has not been indexed, it will
  1103. do a one-off calculation to find the location. It might be very painful if
  1104. someone started using it a lot, without remembering to index the document,
  1105. but it would be handy for things that are only likely to use it once, such
  1106. as error handlers.
  1107.  
  1108. =head1 SUPPORT
  1109.  
  1110. See the L<support section|PPI/SUPPORT> in the main module.
  1111.  
  1112. =head1 AUTHOR
  1113.  
  1114. Adam Kennedy E<lt>adamk@cpan.orgE<gt>
  1115.  
  1116. =head1 COPYRIGHT
  1117.  
  1118. Copyright 2001 - 2010 Adam Kennedy.
  1119.  
  1120. This program is free software; you can redistribute
  1121. it and/or modify it under the same terms as Perl itself.
  1122.  
  1123. The full text of the license can be found in the
  1124. LICENSE file included with this module.
  1125.  
  1126. =cut
  1127.